﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System.Runtime.Serialization;
using System.Collections.Specialized;
using System.Collections;
using System.ComponentModel;
using System.Windows;
using System;
using System.Xml.Serialization;
using System.IO;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BrainTechLLC.ThreadSafeObjects;

namespace BrainTechLLC
{

    public static class FindOptionsExt
    {

        // Inefficient - look into alternative
        public static List<T> Merge<T>(this List<T> items, IEnumerable<T> others, Func<T, bool> match) where T : class
        {
            foreach (T item in others)
            {
                if (items.FindFirst(match) == null)
                {
                    items.Add(item);
                }
            }

            return items;
        }

        public static bool IsFlagSet<T>(this T flags, T match) where T : struct
        {
            int v1 = flags.Int();
            int v2 = match.Int();
            if ((v1 & v2) != 0)
                return true;

            return false;
        }
    }

#if NO_SILVERLIGHT
    [Browsable(true)]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    [EditorBrowsable(EditorBrowsableState.Always)]
    //[TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
#endif
    [DataContract]
    [Serializable]
    public partial class GameThingBaseClass : BaseClass, IKeywordAccessible, INameAndDescription, IHasNameAndDescription, IGameThing, IHasPropertyData, ICanBePlacedInWorld, ICanSaveAndRestore, INotifyPropertyChanged, IFromTemplate, ICanBeNotified, INotifyPropertyChanging, INotifyCollectionChanged
    {
        [XmlIgnore]
        public string ActualType { get { return this.GetType().Name; } }

        public virtual void Notify(INotificationMessage o)
        {
        }

        [XmlIgnore]
        public GameCharTemplate ToGameCharTemplate { get { return this as GameCharTemplate; } }

        [XmlIgnore]
        public Template ToTemplate { get { return this as Template; } }
        /// <summary>
        /// NOTE - will return duplicates if both InWorld and SameRoom flags are used - should not be used with both flags, or caller
        /// needs to handle potential dupes.
        /// </summary>
        /// <returns></returns>
        public List<MatchAndStrength> FindGameThings(string search, float threshold, FindOptions options)
        {
            if (threshold == 0f)
                threshold = 0.55f;

            List<MatchAndStrength> results = new List<MatchAndStrength>();
            float bestWorld, bestRoom;
            bestWorld = bestRoom = 0f;

            List<MatchAndStrength> matchedItemsWorld = null;
            List<MatchAndStrength> matchedItemsRoom = null;

            if (options.IsFlagSet(FindOptions.InWorld) || (options & FindOptions.InWorld) != FindOptions.None)
            {
                bestWorld = search.Find<GameChar>(ref matchedItemsWorld, threshold);
            }
            if (options.IsFlagSet(FindOptions.SameRoom))
            {
                bestRoom = search.Find<GameChar>(ref matchedItemsRoom, threshold);
            }

            if (bestRoom >= 0.5f || bestWorld >= 0.5f)
            {
                if (bestRoom >= 0.5f)
                    results.AddRange(matchedItemsRoom);

                if (bestWorld >= 0.5f)
                    results.AddRange(matchedItemsWorld);
            }

            return results;
        }

        public IGameThing FindGameThing(string search, FindOptions options)
        {
            return this.FindUsingString<IGameThing>(search, 0f, options).FirstOrDefault();
            //float bestWorld, bestRoom;
            //bestWorld = bestRoom = 0f;

            //List<MatchAndStrength> matchedItemsWorld = null;
            //List<MatchAndStrength> matchedItemsRoom = null;

            //if (options.IsFlagSet(FindOptions.InWorld) || (options & FindOptions.InWorld) != FindOptions.None)
            //{
            //    bestWorld = search.Find<GameChar>(ref matchedItemsWorld);
            //}
            //if (options.IsFlagSet(FindOptions.SameRoom))
            //{
            //    bestRoom = search.Find<GameChar>(ref matchedItemsRoom);
            //}

            //if (bestRoom >= 0.5f || bestWorld >= 0.5f)
            //{
            //    if (bestRoom > bestWorld)
            //    {
            //        return matchedItemsRoom[0].MatchedItem as IGameThing;
            //    }
            //    else
            //    {
            //        return matchedItemsWorld[0].MatchedItem as IGameThing;
            //    }
            //}

            //return null;
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
#endif
        [XmlIgnore]
        [DoNotWriteBack]
        public override ITemplate TemplateObject
        {
            get
            {
                if (_templateObject == null)
                    _templateObject = Everything.Find<Template>(TemplateID);
                return _templateObject;
            }
            set
            {
                _templateObject = (Template)value;
                Template t = (Template)value;
                TemplateID = (t == null) ? 0 : t.AssociatedID;
            }
        }

        public override void Save(List<object> arguments)
        {
            if (_lastSaved < _lastChanged || (this is GameChar) || true)
            {
                //#if NO_SILVERLIGHT
                //            string fileName = "C:\\gamething_" + AssociatedID.ToString();
                //            byte[] bytes = this.SerializeToCompressedBinary();
                //            File.WriteAllBytes(fileName, bytes);
                //#endif
                _lastSaved = DateTime.Now;
            }
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
#endif
        [XmlIgnore]
        public virtual GameLocation GameLocation
        {
            get
            {
                GameLocation loc = WorldMap.Instance.FindLocationOfThingID(AssociatedID);

                if (loc == null)
                    loc = this as GameLocation;

                return loc;
            }
        }

//#if NO_SILVERLIGHT
//        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
//#endif
//        public virtual IGameLocation GameLocation
//        {
//            get
//            {
//                GameLocation loc = WorldMap.Instance.FindLocationOfThingID(AssociatedID);

//                if (loc == null)
//                    loc = this as GameLocation;

//                return loc;
//            }
//        }


        public GameThingBaseClass()
        {
        }

        [XmlIgnore]
        public Type ThingType
        {
            get { return this.GetType(); }
        }

        public virtual void PlaceInWorld(List<object> arguments)
        {
        }
                
        ~GameThingBaseClass()
        {
            //if (_dependencies != null)
            //    Dependencies.Clear();
        }


        public override void PerformPostRestoreSetup()
        {
            base.PerformPostRestoreSetup();
            PlaceInWorld(null);

            if (States != null)
            {
                States.LinkUpStates();
                //if (_dependencies == null)
                //{
                //    List<long> ids = States.AllIDs;
                //    for (int n = 0; n < ids.Count; n++)
                //    {
                //        var v = ids[n];
                //        Dependencies.Add(v, null);
                //    }
                //}
            }
        }

        
    }
}
